<template>
  <div class="container">
    <h3 class="h3">测量距离</h3>
    <el-button
      class="bt"
      type="success"
      size="mini"
      @click="distance()"
    >测距</el-button>
    <el-button
      type="danger"
      size="mini"
      @click="cancal()"
    >取消</el-button>
    <div
      id="vue-openlayers"
      ref="map"
    />
  </div>
</template>

<script>
import 'ol/ol.css'
import Draw from 'ol/interaction/Draw'
import Map from 'ol/Map'
import Overlay from 'ol/Overlay'
import View from 'ol/View'
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style'
// import { LineString, Polygon } from 'ol/geom'
import { Vector as VectorSource } from 'ol/source'
import { XYZ } from 'ol/source'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
import { getLength } from 'ol/sphere'
import { unByKey } from 'ol/Observable'

var map = null
var helpTooltipElement = null
var feature = null
var helpTooltip = null
var draw = null
var measureTooltipElement = null
var measureTooltip = null
var listener = null
var mapMouseMove = null

export default {
  name: 'Home',
  data() {
    return {
      drawLayers: [],
      drawElements: []
    }
  },
  mounted() {
    this.initMap()
  },
  methods: {
    // 初始化地图
    initMap() {
      map = new Map({
        layers: [
          new TileLayer({
            source: new XYZ({
              url: 'http://{a-c}.tile.openstreetmap.de/{z}/{x}/{y}.png'
            })
          })
        ],
        target: 'vue-openlayers',
        view: new View({
          center: [113.1206, 23.034996],
          zoom: 5,
          maxZoom: 18,
          projection: 'EPSG:4326',
          constrainResolution: true, // 设置缩放级别为整数
          smoothResolutionConstraint: false // 关闭无级缩放地图
        })
      })
    },

    // 测距
    distance() {
      const source = new VectorSource() // 创建一个数据源，用来放置绘制过程中和绘制结束后的线段
      const layer = new VectorLayer({ // 添加一个图层，用来放置数据源
        source: source,
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new Stroke({
            color: '#ffcc33',
            width: 4
          }),
          image: new CircleStyle({
            radius: 7,
            fill: new Fill({
              color: '#ffcc33'
            })
          })
        })
      })
      // 给地图添加一个鼠标移动事件
      mapMouseMove = map.on('pointermove', (ev) => {
        let helpMsg = '点击开始测量' // 默认开始的操作提示文本
        if (feature) { // featuer 是全局的，判断有没有点击鼠标绘制过
          helpMsg = '双击结束测量'// 如果之前点击绘制了就显示双击结束
        }
        helpTooltipElement.innerHTML = helpMsg // 设置dom的提示文字
        helpTooltip.setPosition(ev.coordinate) // 设置位置跟着鼠标走
        helpTooltipElement.classList.remove('hidden')
      })
      map.getViewport().addEventListener('mouseout', function() {
        helpTooltipElement.classList.add('hidden')
      })

      draw = new Draw({
        source, // 这个数据源就是我们最开始的那个数据源，这是简写，实际上是 source:source
        type: 'LineString',
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new Stroke({
            color: 'rgba(0, 0, 0, 0.5)',
            lineDash: [10, 10],
            width: 4
          }),
          image: new CircleStyle({
            radius: 5,
            stroke: new Stroke({
              color: 'rgba(0, 0, 0, 0.7)'
            }),
            fill: new Fill({
              color: 'rgba(255, 255, 255, 0.2)'
            })
          })
        })
      })

      // 开始监听绘制
      draw.on('drawstart', (evt) => {
        feature = evt.feature
        let tooltipCoord = evt.coordinate // 鼠标当前的位置
        listener = feature.getGeometry().on('change', function(evt) {
          const geom = evt.target
          const output = formatLength(geom)
          tooltipCoord = geom.getLastCoordinate()// 设置鼠标位置改变后的实时位置
          measureTooltipElement.innerHTML = output// 设置提示框的内容，就是距离
          measureTooltip.setPosition(tooltipCoord) // 设置距离提示框的位置
        })
      })

      // 双击绘制完成
      draw.on('drawend', () => {
        measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
        measureTooltip.setOffset([0, -7])
        feature = null
        measureTooltipElement = null
        this.createMeasureTooltip()
        unByKey(listener)
      })

      // 格式化长度
      const formatLength = function(line) {
        const length = getLength(line)
        let output
        if (length > 100) {
          output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km'
        } else {
          output = Math.round(length * 100) / 100 + ' ' + 'm'
        }
        return output
      }

      this.createHelpTooltip()// 创建那个距离的提示框
      this.createMeasureTooltip()
      map.addLayer(layer)
      this.drawLayers.push(layer)
      map.addInteraction(draw)
    },

    // 取消绘制
    cancal() {
      for (let i = 0; i < this.drawLayers.length; i++) {
        map.removeLayer(this.drawLayers[i])
      }
      for (let i = 0; i < this.drawElements.length; i++) {
        map.removeOverlay(this.drawElements[i])
      }
      this.drawLayers = []
      this.drawElements = []
      map.removeInteraction(draw)
      unByKey(mapMouseMove)
    },

    createMeasureTooltip() {
      if (measureTooltipElement) {
        measureTooltipElement.parentNode.removeChild(measureTooltipElement)
      }
      measureTooltipElement = document.createElement('div')
      measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure'
      measureTooltip = new Overlay({
        element: measureTooltipElement,
        offset: [0, -15],
        positioning: 'bottom-center',
        stopEvent: false,
        insertFirst: false
      })
      this.drawElements.push(measureTooltip)
      map.addOverlay(measureTooltip)
    },

    createHelpTooltip() {
      if (helpTooltipElement) {
        helpTooltipElement.parentNode.removeChild(helpTooltipElement)
      }
      helpTooltipElement = document.createElement('div')
      helpTooltipElement.className = 'ol-tooltip hidden'
      helpTooltip = new Overlay({
        element: helpTooltipElement,
        offset: [15, 0],
        positioning: 'center-left'
      })
      map.addOverlay(helpTooltip)
    }
  }
}

</script>
<style scoped>
.container {
  width: 1240px;
  height: 690px;
  margin: 50px auto;
  border: 1px solid #42b983;
}

#vue-openlayers {
  width: 1200px;
  height: 570px;
  margin: 0 auto;
  margin-top: 10px;
  border: 1px solid #42b983;
  position: relative;
}

.set {
  position: absolute;
  top: 0px;
  right: 0px;
  z-index: 99;
}
.h3 {
  text-align: center;
}
.bt {
   margin-left: 550px;
}
.hidden {
  display: none;
}

.ol-tooltip {
  position: relative;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  opacity: 0.7;
  white-space: nowrap;
  font-size: 12px;
  cursor: default;
  user-select: none;
}

.ol-tooltip-measure {
  opacity: 1;
  font-weight: bold;
}

.ol-tooltip-static {
  background-color: #ffcc33;
  color: black;
  border: 1px solid white;
}

.ol-tooltip-measure:before,
.ol-tooltip-static:before {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

.ol-tooltip-static:before {
  border-top-color: #ffcc33;
}
</style>
